package com.hainiu.cat.interview.juc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * create by biji.zhao on 2021/7/2
 */
public class PC {

    private int number;

    private int status;

    Lock lock = new ReentrantLock();
    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();

    private synchronized void decrement() throws InterruptedException {
        while (number == 0) {
            wait();
        }

        number -- ;
        System.out.println(Thread.currentThread().getName() + "==>" + number);
        notifyAll();
    }

    private synchronized void increment() throws InterruptedException {
        while (number != 0) {
            wait();
        }
        number ++ ;
        System.out.println(Thread.currentThread().getName() + "==>" + number);
        notifyAll();
    }

    private void decrementLock() throws InterruptedException {
        lock.lock();
        try {
            while (number == 0) {
                condition1.await();
            }
            number -- ;
            System.out.println(Thread.currentThread().getName() + "==>" + number);
            condition1.signalAll();
        }finally {
            lock.unlock();
        }
    }

    private void incrementLock() throws InterruptedException {
        lock.lock();
        try {
            while (number != 0) {
                condition1.await();
            }
            number ++ ;
            System.out.println(Thread.currentThread().getName() + "==>" + number);
            condition1.signalAll();
        }finally {
            lock.unlock();
        }
    }

    private void caring() throws InterruptedException{
        lock.lock();
        try {
            while (status != 0) {
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + "==> 开车");
            status = 1;
            condition2.signal();
        }finally {
            lock.unlock();
        }
    }

    private void working() throws InterruptedException{
        lock.lock();
        try {
            while (status != 1) {
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName() + "==> 工作");
            status = 2;
            condition3.signal();
        }finally {
            lock.unlock();
        }
    }

    private void eating() throws InterruptedException {
        lock.lock();
        try {
            while (status != 2) {
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName() + "==> 吃饭");
            System.out.println();
            status = 0;
            condition1.signal();
        }finally {
            lock.unlock();
        }
    }

    private static void testSortExecute() {
        PC pc = new PC();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    pc.caring();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    pc.working();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    pc.eating();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
    }

    private static void testPcLock() {
        PC pc = new PC();

        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                try {
                    pc.decrementLock();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    pc.incrementLock();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
    }

    private static void testPcSynchronized() {
        PC pc = new PC();

        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                try {
                    pc.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    pc.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
    }


    public static void main(String[] args) throws Exception {
//        testPcSynchronized();
//        testPcLock();
//        testSortExecute();


        Util util = new Util();
        Util util2 = new Util();
        // 如果是static方法，锁的是Util.class
        new Thread(() -> util.sendSms(), "A").start();
        new Thread(() -> util2.call(), "B").start();
    }
}

class Util {
    public static synchronized void sendSms () { System.out.println("发短信"); }
    public static synchronized void call () { System.out.println("打电话"); }
}
